﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Messaging;
using System.Windows.Threading;

namespace Helper
{
    public class CommunicatorService : ServiceBase
    {
        private const string End = "End";
        private const string Master = "Master";
        private const string OK = "OK";
        private const string Start = "Start";

        private LocalMessageReceiver masterReceiver;
        private LocalMessageSender masterSender;
        private DispatcherTimer masterTimer;
        private LocalMessageReceiver receiver;
        private IList<LocalMessageSender> senders = new List<LocalMessageSender>();
        private DispatcherTimer timer;
        private const int TimerInterval = 0x7530;

        [ScriptableMember]
        public event EventHandler<MessageEventArgs> MessageReceived;
        [ScriptableMember]
        public event EventHandler<MessageEventArgs> SendCompleted;

        public static CommunicatorService Current { get; set; }

        private bool _isActive = false;
        [ScriptableMember]
        public bool IsActive
        {
            get { return this._isActive; }
            private set { base.SetPropertyValue<bool>(ref this._isActive, value, () => this.IsActive); }
        }

        private bool _isMaster = false;
        [ScriptableMember]
        public bool IsMaster
        {
            get { return this._isMaster; }
            private set { base.SetPropertyValue<bool>(ref this._isMaster, value, () => this.IsMaster); }
        }

        private string _receiverName = "";
        [ScriptableMember]
        public string ReceiverName
        {
            get { return this._receiverName; }
            set { base.SetPropertyValue<string>(ref this._receiverName, value, () => this.ReceiverName, this.InitializeReceiver); }
        }

        private int _senderCount = 0;
        [ScriptableMember]
        public int SenderCount
        {
            get { return this._senderCount; }
            private set { base.SetPropertyValue<int>(ref this._senderCount, value, () => this.SenderCount); }
        }

        private string _senderNames = "";
        [ScriptableMember]
        public string SenderNames
        {
            get { return this._senderNames; }
            private set { base.SetPropertyValue<string>(ref this._senderNames, value, () => this.SenderNames, this.SynchorinizeSenders); }
        }

        private IList<string> SenderNamesList
        {
            get { return new List<string>(this.SenderNames.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); }
        }

        private void DisposeMasterReceiver()
        {
            if (this.masterReceiver != null)
            {
                this.masterReceiver.MessageReceived -= new EventHandler<MessageReceivedEventArgs>(this.MasterMessageReceived);
                this.masterReceiver.Dispose();
                this.masterReceiver = null;
            }
        }

        private void DisposeReceiver()
        {
            if (this.receiver != null)
            {
                this.receiver.MessageReceived -= new EventHandler<MessageReceivedEventArgs>(this.OnMessageReceived);
                this.receiver.Dispose();
                this.receiver = null;
            }
        }

        private string EnhanceMessage(string message)
        {
            return this.EnhanceMessage(message, this.ReceiverName);
        }

        private string EnhanceMessage(string message, string receiver)
        {
            return (receiver + "|" + message);
        }

        private void InitializeMasterReceiver()
        {
            EventHandler handler = null;
            this.IsMaster = false;
            try
            {
                this.masterReceiver = new LocalMessageReceiver("Master", ReceiverNameScope.Global, LocalMessageReceiver.AnyDomain);
                this.masterReceiver.MessageReceived += new EventHandler<MessageReceivedEventArgs>(this.MasterMessageReceived);
                this.masterReceiver.Listen();
                this.IsMaster = true;
                this.masterTimer = new DispatcherTimer();
                this.masterTimer.Interval = TimeSpan.FromMilliseconds(30000.0);
                if (handler == null)
                {
                    handler = delegate (object s, EventArgs e) {
                        this.MasterSendMessage(this.SenderNames);
                    };
                }
                this.masterTimer.Tick += handler;
                this.masterTimer.Start();
            }
            catch (Exception)
            {
            }
        }

        private void InitializeReceiver()
        {
            this.IsActive = false;
            this.DisposeReceiver();
            if (!string.IsNullOrEmpty(this.ReceiverName))
            {
                try
                {
                    this.receiver = new LocalMessageReceiver(this.ReceiverName, ReceiverNameScope.Global, LocalMessageReceiver.AnyDomain);
                    this.receiver.MessageReceived += new EventHandler<MessageReceivedEventArgs>(this.OnMessageReceived);
                    this.receiver.Listen();
                    this.SendMessageToMaster("Start");
                    this.IsActive = true;
                }
                catch (Exception exception)
                {
                    base.ReportErrorToDOM(exception);
                }
            }
        }

        private void MasterMessageReceived(object sender, MessageReceivedEventArgs e)
        {
            string[] strArray = this.SplitMessage(e.Message);
            IList<string> senderNamesList = this.SenderNamesList;
            string str = strArray[1];
            if (str != null)
            {
                if (!(str == "Start"))
                {
                    if ((str == "End") && senderNamesList.Contains(strArray[0]))
                    {
                        senderNamesList.Remove(strArray[0]);
                    }
                }
                else if (!senderNamesList.Contains(strArray[0]))
                {
                    senderNamesList.Add(strArray[0]);
                }
            }
            e.Response = "OK";
            this.SenderNames = string.Join(";", senderNamesList);
            this.MasterSendMessage(this.SenderNames);
        }

        private void MasterSendCompleted(object sender, SendCompletedEventArgs e)
        {
            if ((e.Error != null) && !this.IsMaster)
            {
                this.InitializeMasterReceiver();
                this.SendMessageToMaster("Start");
            }
        }

        private void MasterSendMessage(string message)
        {
            foreach (LocalMessageSender sender in this.senders)
            {
                sender.SendAsync(this.EnhanceMessage(message, "Master"));
            }
        }

        private void MessageFromMaster(string message)
        {
            string str = message;
            if ((str == null) || (str != "End"))
            {
                this.SenderNames = message;
            }
            else
            {
                this.InitializeMasterReceiver();
                this.SendMessageToMaster("Start");
            }
        }

        private void OnMessageReceived(object sender, MessageReceivedEventArgs e)
        {
            string[] strArray = this.SplitMessage(e.Message);
            if (strArray[0] == "Master")
            {
                this.MessageFromMaster(strArray[1]);
            }
            else
            {
                MessageEventArgs args = new MessageEventArgs(strArray[0], e.ReceiverName, strArray[1], null, null);
                if (this.MessageReceived != null) this.MessageReceived(this, args);
                e.Response = args.Response;
            }
        }

        private void OnSendCompleted(object sender, SendCompletedEventArgs e)
        {
            string[] strArray = this.SplitMessage(e.Message);
            if (e.Error != null)
            {
                base.ReportErrorToDOM(e.Error);
                if (strArray[0] == "Master")
                {
                    IList<string> senderNamesList = this.SenderNamesList;
                    if (senderNamesList.Contains(e.ReceiverName))
                    {
                        senderNamesList.Remove(e.ReceiverName);
                        this.SenderNames = string.Join(";", senderNamesList);
                        this.MasterSendMessage(this.SenderNames);
                    }
                }
            }
            if (strArray[0] != "Master")
            {
                MessageEventArgs args = new MessageEventArgs(strArray[0], e.ReceiverName, strArray[1], (e.Error == null) ? e.Response : null, (e.Error != null) ? e.Error.Message : null);
                if (this.SendCompleted != null)  this.SendCompleted(this, args);
            }
        }

        [ScriptableMember]
        public void ReSynchronize()
        {
            this.SendMessageToMaster("Start");
        }

        [ScriptableMember]
        public void Send(string message)
        {
            this.Send(message, null);
        }

        [ScriptableMember]
        public void Send(string message, string receiver)
        {
            foreach (LocalMessageSender sender in this.senders)
            {
                if (string.IsNullOrEmpty(receiver) || (sender.ReceiverName == receiver))
                {
                    sender.SendAsync(this.EnhanceMessage(message));
                }
            }
        }

        private void SendMessageToMaster(string message)
        {
            this.masterSender.SendAsync(this.EnhanceMessage(message));
        }

        private string[] SplitMessage(string message)
        {
            int index = message.IndexOf('|');
            return new string[] { message.Substring(0, index), message.Substring(index + 1) };
        }

        protected override void StartService(ApplicationServiceContext context)
        {
            EventHandler handler = null;
            try
            {
                this.masterSender = new LocalMessageSender("Master", "*");
                this.masterSender.SendCompleted += new EventHandler<SendCompletedEventArgs>(this.MasterSendCompleted);
                this.timer = new DispatcherTimer();
                this.timer.Interval = TimeSpan.FromMilliseconds(30000.0);
                if (handler == null)
                {
                    handler = delegate (object s, EventArgs e) {
                        this.SendMessageToMaster("OK");
                    };
                }
                this.timer.Tick += handler;
                this.timer.Start();
                this.InitializeMasterReceiver();
                Dictionary<string, string> applicationInitParams = context.ApplicationInitParams;
                if (applicationInitParams.ContainsKey("ReceiverName"))
                {
                    this.ReceiverName = applicationInitParams["ReceiverName"];
                }
                Current = this;
            }
            catch (Exception exception)
            {
                base.ReportErrorToDOM(exception);
            }
            HtmlPage.RegisterScriptableObject("Communicator", this);
        }

        protected override void StopService()
        {
            this.timer.Stop();
            this.DisposeReceiver();
            if (!this.IsMaster)
            {
                this.SendMessageToMaster("End");
            }
            else
            {
                this.DisposeMasterReceiver();
                IList<string> senderNamesList = this.SenderNamesList;
                senderNamesList.Remove(this.ReceiverName);
                this.MasterSendMessage(string.Join(";", senderNamesList));
                this.MasterSendMessage("End");
                this.masterTimer.Stop();
            }
            Current = null;
        }

        private void SynchorinizeSenders()
        {
            LocalMessageSender sender;
            IList<string> senderNamesList = this.SenderNamesList;
            Dictionary<string, LocalMessageSender> dictionary = this.senders.ToDictionary<LocalMessageSender, string>(s => s.ReceiverName);
            IEnumerable<string> enumerable = senderNamesList.Except<string>(dictionary.Keys);
            IEnumerable<string> enumerable2 = dictionary.Keys.Except<string>(senderNamesList);
            foreach (string str in enumerable)
            {
                if (str != this.ReceiverName)
                {
                    sender = new LocalMessageSender(str, "*");
                    sender.SendCompleted += new EventHandler<SendCompletedEventArgs>(this.OnSendCompleted);
                    this.senders.Add(sender);
                }
            }
            foreach (string str in enumerable2)
            {
                sender = dictionary[str];
                sender.SendCompleted -= new EventHandler<SendCompletedEventArgs>(this.OnSendCompleted);
                this.senders.Remove(sender);
            }
            if (!senderNamesList.Contains(this.ReceiverName))
            {
                this.SendMessageToMaster("Start");
            }
            this.SenderCount = senderNamesList.Count;
        }

       




        


    }
}

